using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using The_LarX.Rendering;

namespace The_LarX
{
    public class GameScreen : ILoadeable, IComparable<GameScreen>
    {
        private int drawOrder;
        public int DrawOrder
        {
            get { return drawOrder; }
            set
            {
                drawOrder = value;
                if (Engine.GameScreens.Contains(this))
                {
                    Engine.GameScreens.Order();
                }
            }
        }

        public static Comparison<GameScreen> DrawOrderComparison = delegate(GameScreen g1, GameScreen g2)
        {
            return g1.DrawOrder.CompareTo(g2.DrawOrder);
        };


        public int CompareTo(GameScreen other)
        {
            return DrawOrder.CompareTo(other.DrawOrder);
        }


        #region Variables
        /// <summary>
        /// The GameScreen name
        /// </summary>
        public string Name;

        private static int i;

        public bool CanDisable = true;

        /// <summary>
        /// The Components of this GameScreen
        /// </summary>
        public ComponentCollection Components;

        /// <summary>
        /// If the GameScreen should Update and Draw
        /// </summary>
        public bool Visible = true;

        /// <summary>
        /// A Collection of Data for serialization
        /// </summary>
        public SerializeData Data;

        public bool Loaded { get; set; }      
        public bool OverrideLoaded = true;

        #endregion

        #region Constructors
        /// <summary>
        /// Constructor 1
        /// </summary>
        /// <param name="Name">The GameScreen name</param>
        public GameScreen(string Name)
        {
            if (!Engine.Initialized)
            {
                throw new Exception("ENGINE NOT INITIALIZED, initialize it with Engine.LoadEngine(...)");
            }
            else
            {
                if (Engine.GameScreens.Contains(Name))
                {
                    this.Name = GenerateRandomName(Name);
                }
                else
                {
                    this.Name = Name;
                    Charge();
                }
            }
        }

        /// <summary>
        /// Constructor 2
        /// </summary>
        public GameScreen()
        {
            if (!Engine.Initialized)
            {
                throw new Exception("ENGINE NOT INITIALIZED, initialize it with Engine.LoadEngine(...)");
            }
            else
            {
                this.Name = GenerateRandomName(null);
                Charge();
            }
        }


        /// <summary>
        /// Constructor
        /// </summary>
        public GameScreen(ScreenManager Manager)
        {
            this.ScreenManager = Manager;
            if (!Engine.Initialized)
            {
                throw new Exception("ENGINE NOT INITIALIZED, initialize it with Engine.LoadEngine(...)");
            }
            else
            {
                this.Name = GenerateRandomName(null);
                Charge();
                Engine.GameScreens.Remove(this);
                this.ScreenInfo = Manager.Add(this);
            }
        }

        public ScreenManager ScreenManager { get; protected set; }
        public ScreenInfo ScreenInfo { get; protected set; }

        public Vector2 Position { get; set; }

        public virtual void VisibilityChange(bool visibility)
        {
        }

        public virtual void Load()
        {
            
        }

        private void Charge()
        {
            Data = new SerializeData(this.GetType().ToString());
            Engine.GameScreens.Add(this);
            Components = new ComponentCollection();
        }
        
        private void ReLoad()
        {
            Engine.GameScreens.Remove(this);
            Engine.GameScreens.Add(this);
            Components = new ComponentCollection();

        }

        #endregion

        #region Private Methods
        private static string GenerateRandomName(string PreviousName)
        {
            string finalName;

            i++;

            if (PreviousName == null)
            {
                finalName = "GameScreen";
                StringBuilder Builder = new StringBuilder(finalName);
                Builder.Append(i);

                return Builder.ToString();
            }
            else
            {
                finalName = PreviousName;
                StringBuilder Builder = new StringBuilder(finalName);
                Builder.Append(i);

                return Builder.ToString();
            }
        }

        #endregion

        #region Public Methods
        protected Render2Texture RenderTexture;
        public Texture2D RenderScreen()
        {
            if (RenderTexture == null)
                RenderTexture = new Render2Texture();

            RenderTexture.BackgroundColor = Color.Transparent;
            RenderTexture.ClearBackground = true;
            RenderTexture.BeginRender();
            Draw();
            RenderTexture.EndRender();

            return RenderTexture.RenderTarget;
        }


        public virtual void Update()
        {
            if (OverrideLoaded || Loaded)
            {
                if (Visible)
                {
                    for (int j = 0; j < Components.Count; j++)
                    {
                        if (Components[j].Visible)
                            Components[j].Update();
                    }
                }
            }
        }

        public virtual void Draw()
        {
            if (OverrideLoaded || Loaded)
            {
                if (Visible)
                {
                    for (int j = 0; j < Components.Count; j++)
                    {
                        if (Components[j].Visible)
                            Components[j].Draw();
                    }
                }
            }
        }

        public virtual void DrawOnDebugMode()
        {
            if (OverrideLoaded || Loaded)
            {
                if (Visible)
                {
                    for (int j = 0; j < Components.Count; j++)
                    {
                        if (Components[j].Visible)
                            Components[j].DrawOnDebugMode();
                    }
                }
            }
        }

        /// <summary>
        /// Disables this GameScreen and all of it's Components
        /// </summary>
        public virtual void Disable()
        {
            for (int j = 0; j < Components.Count; j++)
            {
                Components[j].DisableComponent();
            }
            Components.Clear();

            if (Engine.GameScreens.Contains(this))
                Engine.GameScreens.Remove(this);
        }
        public virtual void AddComponent(Component Comp)
        {
            this.Components.Add(Comp);
        }
        public virtual void RemoveComponent(Component Comp)
        {
            this.Components.Remove(Comp);
        }
        public virtual Component GetComponent(string name)
        {
            return Components[name];
        }
        public virtual void AddComponent(Component Comp, int Index)
        {
            this.Components.Insert(Index, Comp);
        }
        #endregion

        #region Serialization
        public virtual void SerializeData()
        {
            Data.Data.Clear();
            Data.AddData("GameScreen.Name", this.Name);
        }
        public virtual void DeserializeData()
        {
            Components = new ComponentCollection();
            this.Name = Data.GetData<string>("GameScreen.Name");
            ReLoad();
        }
        #endregion

        public override string ToString()
        {
            return this.Name;
        }
    }
}
